package servlets;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;

import entities.User;

import queries.DBConnector;
import queries.SecurityQueries;
import queries.UploadQueries;
import queries.UserManagementQueries;

/**
 * Servlet implementation class UploadRecord
 */
@WebServlet("/UploadRecord")
public class UploadRecord extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public UploadRecord() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Map<String, String> messages = new HashMap<String, String>();
		request.setAttribute("messages", messages);
		DBConnector dbConnect = new DBConnector();
		SecurityQueries security = null;
		
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
		// Create a factory for disk-based file items
		DiskFileItemFactory factory = new DiskFileItemFactory();

		// Create a new file upload handler
		ServletFileUpload upload = new ServletFileUpload(factory);

		// Parse the request
		try {
			security = new SecurityQueries(dbConnect.getConnection());
			UserManagementQueries umq = new UserManagementQueries(dbConnect.getConnection(), security);				
			List items = upload.parseRequest(request);
			File largeFile = null;
			File regularFile = null;
			File thumbFile = null;
			ArrayList<ArrayList<File>> imgList = new ArrayList<ArrayList<File>>();
			DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
			String patient_name = null; 
			String doctor_name = null; 
			String radiologist_name = null;
			String test_type = null;
			String diagnosis = null; 
			String description = null;
			java.util.Date pd = null;
			java.util.Date td = null;

			Iterator iter = items.iterator();			
			
			//Loop over all the fields in the request
			while(iter.hasNext()) {
				FileItem item = (FileItem) iter.next();
				
				if(item.isFormField()) {
					if(item.getFieldName().equals("patient_name")) {
						try {
							if(validatePatientName(item.getString(), umq)) {
								patient_name = item.getString();
								System.out.println(patient_name);
							} else {
								messages.put("new_record_msg", "<span class=\"message error\">Invalid patient name.</span>");
								request.getRequestDispatcher("addRecord.jsp").forward(request, response);
								return;
							}
						} catch (SQLException e) {
							messages.put("new_record_msg", "<span class=\"message error\">This patient does not exist.</span>");
							request.getRequestDispatcher("addRecord.jsp").forward(request, response);
							e.printStackTrace();
							return;	
						}
					}
					else if(item.getFieldName().equals("doctor_name")) {
						try {
							if(validateDoctorName(item.getString(), patient_name, umq)) {
								doctor_name = item.getString();
								System.out.println(doctor_name);								
							} else {
								messages.put("new_record_msg", "<span class=\"message error\">Invalid doctor name.</span>");
								request.getRequestDispatcher("addRecord.jsp").forward(request, response);	
								return;
							}
						} catch (SQLException e) {
							messages.put("new_record_msg", "<span class=\"message error\">This doctor does not exist.</span>");
							request.getRequestDispatcher("addRecord.jsp").forward(request, response);
							e.printStackTrace();
							return;	
						}
					}
					else if(item.getFieldName().equals("radiologist_name")) {
						try {
							if(validateRadiologistName(item.getString(), umq)) {
								radiologist_name = item.getString();
								System.out.println(radiologist_name);								
							} else {
								messages.put("new_record_msg", "<span class=\"message error\">Invalid radiologist name.</span>");
								request.getRequestDispatcher("addRecord.jsp").forward(request, response);
								return;
							}
						} catch (SQLException e) {
							messages.put("new_record_msg", "<span class=\"message error\">This radiologist does not exist.</span>");
							request.getRequestDispatcher("addRecord.jsp").forward(request, response);
							e.printStackTrace();
							return;							
						}
					}
					else if(item.getFieldName().equals("prescribing_date")) {
						pd = df.parse(item.getString());	
						System.out.println(pd);						
					}
					else if(item.getFieldName().equals("test_date")) {
						td = df.parse(item.getString());	
						System.out.println(td);						
					}
					else if(item.getFieldName().equals("test_type")) {
						test_type = item.getString();
						System.out.println(test_type);						
					}					
					else if(item.getFieldName().equals("diagnosis")) {
						diagnosis = item.getString();
						System.out.println(diagnosis);						
					}
					else if(item.getFieldName().equals("description")) {
						description = item.getString();
						System.out.println(description);						
					}					
				
				/* Process the uploaded file */		
				} else if (!item.getName().equals("")) {

					System.out.println("Uploading a file");
					InputStream instream = item.getInputStream();
					
					/*Create the files */
					largeFile = new File(getServletContext().getRealPath("/")+"large_"+item.getName());
					regularFile = new File(getServletContext().getRealPath("/")+"regular_"+item.getName());
					thumbFile = new File(getServletContext().getRealPath("/")+"thumb_"+item.getName());						
					
					/* Create and resize the images */
					BufferedImage img_large = ImageIO.read(instream);
					BufferedImage img_regular = shrink(img_large, 800, 800);
					BufferedImage img_thumb = shrink(img_large, 100, 100);
					
					/* Write the images to the files */
					ImageIO.write(img_large,"jpg", largeFile);
					ImageIO.write(img_regular,"jpg", regularFile);
					ImageIO.write(img_thumb,"jpg", thumbFile);
					
					ArrayList<File> sizes = new ArrayList<File>();
					sizes.add(largeFile);
					sizes.add(regularFile);
					sizes.add(thumbFile);

					imgList.add(sizes);
				}
				
			} /* End of while loop */
			
			/* Now we have all the required fields, and they've all been validated, so we can put them in the database. */
			java.sql.Date prescribing_date = new java.sql.Date(pd.getTime());
			java.sql.Date testing_date = new java.sql.Date(td.getTime());			
			
			UploadQueries upq = new UploadQueries(dbConnect.getConnection(), security);
			int recordID = upq.createRadRecord(
							patient_name, 
							doctor_name, 
							radiologist_name, 
							test_type, 
							prescribing_date, 
							testing_date, 
							diagnosis, 
							description
						);				
			
			/* The record has been added, so now we add the images */
			for(ArrayList<File> allSizes : imgList) {
				upq.addMysqlPacsImage(recordID, allSizes.get(2), allSizes.get(1), allSizes.get(0));
			}
			System.out.println(recordID);
			
			messages.put("new_record_msg", "<span class=\"message success\">New record added.</span>");
			request.getRequestDispatcher("addRecord.jsp").forward(request, response);			
			
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParseException e) {
			messages.put("new_record_msg", "<span class=\"message error\">Invalid date entered.</span>");
			request.getRequestDispatcher("addRecord.jsp").forward(request, response);	
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			messages.put("new_record_msg", "<span class=\"message error\">Record could not be uploaded.</span>");
			request.getRequestDispatcher("addRecord.jsp").forward(request, response);	
			e.printStackTrace();
		}
	}
	
	private boolean validateDoctorName(String doctor_name, String patient_name, UserManagementQueries umq) throws SQLException {
		//Make sure the doctor's name isn't blank
		if(doctor_name.equals("")) {
			return false;
		}			
		
		//Make sure doctor is one of the patient's family doctors.
		ArrayList<String> doctorList = umq.retrieveDoctorNames(patient_name);
		if(!doctorList.contains(doctor_name)) {
			return false;				
		}
		
		return true;
	}
	
	private boolean validatePatientName(String patient_name, UserManagementQueries umq) throws SQLException {
		//Make sure the patient name isn't blank.
		if(patient_name.equals("")) {
			return false;
		}
		
		//Make sure the patient exists.
		try {
			umq.retrieveUserData(patient_name);
		} catch (SQLException e) {
			return false;
		}
		
		return true;
	}
	
	private boolean validateRadiologistName(String radiologist_name, UserManagementQueries umq) throws SQLException {
		//Make sure the radiologist's name isn't blank
		if(radiologist_name.equals("")) {
			return false;
		}			
		
		//Make sure the selected person really is a radiologist
		try {
			User radiologist = umq.retrieveUserData(radiologist_name);
			if(!radiologist.getUserClass().equals("r")) {		
				return false;
			}
		} catch (SQLException e) {
			return false;
		}
		
		return true;
	}
	
    public static BufferedImage shrink(BufferedImage image, int maxWidth, int maxHeight) {
        
        float xScale = (float) (maxWidth * 1.0) / image.getWidth();
        float yScale = (float) (maxHeight * 1.0) / image.getHeight();
        int newWidth, newHeight;
        
        //Image is tall
        if (xScale > yScale) {
        	float scale = yScale;
        	newHeight = maxHeight;
        	newWidth = (int) Math.round( image.getWidth() * scale);
        }
        //Image is wide
        else {
        	float scale = xScale;
        	newWidth = maxWidth;
        	newHeight = (int) Math.round( image.getHeight() * scale);
        }
        
        
        BufferedImage scaledImage =
            new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);

        Graphics2D graphics2D = scaledImage.createGraphics();
        graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
        	RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        graphics2D.drawImage(image, 0, 0, newWidth, newHeight, null);

        // clean up
        graphics2D.dispose();

        return scaledImage;
    }	

}
